package com.kxf.androidtestdemo.util;

import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.MotionEvent;

import com.kxf.androidtestdemo.view.OutSideView;
import com.kxf.utils.StackTracesUtil;

import java.util.ArrayList;
import java.util.Arrays;

import de.robv.android.xposed.DexposedBridge;
import de.robv.android.xposed.XC_MethodHook;

public class EpicHookUtils {
    private static final String TAG = "EpicHookUtils";

    private EpicHookUtils() {
    }

    public static void hook(){
//        hookMethod(OutSideView.class, "onTouchEvent", null, MotionEvent.class);
        hookMethod(TelephonyManager.class, "getTypeAllocationCode", null);
    }

    public static void hookMethod(Class<?> clazz, String methodName, XC_MethodHook methodHook, Object... parameterTypes){
        Object[] parameterTypesAndCallback = null;
        if (methodHook==null){
            methodHook = new MyMethodHook();
        }
        if (parameterTypes!=null && parameterTypes.length>0){
            ArrayList<Object> os = new ArrayList<>();
            os.addAll(Arrays.asList(parameterTypes));
            os.add(methodHook);
            parameterTypesAndCallback = os.toArray();
        }else {
            parameterTypesAndCallback = new Object[]{methodHook};
        }
        try {
            Object[] finalParameterTypesAndCallback = parameterTypesAndCallback;
            DexposedBridge.hookAllConstructors(clazz, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Class<?> mClazz = param.thisObject.getClass();
                    if (clazz != mClazz) {
                        Log.d(TAG, "hookAllConstructors not found class :" + clazz);
                        DexposedBridge.findAndHookMethod(mClazz, methodName, finalParameterTypesAndCallback);
                    }
                    Log.d(TAG, "hookAllConstructors class:" + mClazz +  " is created.");
                }
            });
            DexposedBridge.findAndHookMethod(clazz, methodName, parameterTypesAndCallback);
            Log.d(TAG, "hookMethod==>>>");
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    static class MyMethodHook extends XC_MethodHook {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            Log.i(TAG, "MyMethodHook beforeHookedMethod:" + param.thisObject + "==>>" + param.method + "==>>" + Arrays.toString(param.args));
            StackTracesUtil.printCurrent();
        }

        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            Log.i(TAG, "MyMethodHook afterHookedMethod:" + param.thisObject + "==>>" + param.method + "==>>" + Arrays.toString(param.args));
        }
    }
}
